package k1_jdbc.tool;

import java.sql.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class ConnectionTool {

    private static Connection conn = null;
    private static PreparedStatement ps = null;

    static{
        try {
            //加载数据库驱动
            Class.forName(Const.DRIVER);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 按照默认情况获取连接
     * @return
     * @throws SQLException
     */
    public static Connection getDefaultConn() throws SQLException {
        return DriverManager.getConnection(
                Const.URL_TEST,
                Const.USERNAME,
                Const.PASSWORD
        );
    }

    /**
     * 指定数据库获取连接
     * @return
     * @throws SQLException
     */
    public static Connection getDefaultConn(String database) throws SQLException {
        return DriverManager.getConnection(
                Const.URL+database,
                Const.USERNAME,
                Const.PASSWORD
        );
    }


    /**
     * 关闭 连接和预处理
     * @param conn
     * @param ps
     */
    public static void closed(Connection conn, PreparedStatement ps){
        closed(conn,ps,null);
    }

    /**
     * 关闭连接 预处理和结果集
     * @param conn
     * @param ps
     * @param rs
     */
    public static void closed(Connection conn, PreparedStatement ps, ResultSet rs){
        try {
            if(rs!=null){
                rs.close();
            }
            if(ps!=null){
                ps.close();
            }
            if(conn!=null){
                conn.close();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 关闭当前类中的连接和预处理
     */
    public static void closed(){
        try {
            if(ps!=null){
                ps.close();
            }
            if(conn!=null){
                conn.close();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 执行单条增删改语句，最终调用批处理执行
     * @param sql 要执行的语句
     * @param args 单条预处理语句中每个问号对应的值，顺序必须与问号顺序保持一致
     * @return
     */
    public static boolean executeUpdateSql(String sql,Object[] args){
        //把单条数据转成集合，然后以多条数据的形式调用重载方法
        List<Object[]> objList = new ArrayList<>();
        objList.add(args);
        return executeUpdateSql(sql,objList);
    }

    /**
     * 执行批处理增删改语句
     * @param sql 要执行的语句
     * @param args 多条数据的参数值，每条数据的参数值以 Object[] 的形式传递
     * @return
     */
    public static boolean executeUpdateSql(String sql, List<Object[]> args){

        //初始化运行结果的返回值
        boolean result = true;

        try{
            //获取连接并关闭自动提交事务
            conn = getDefaultConn();
            conn.setAutoCommit(false);

            //初始化预处理语句
            ps = conn.prepareStatement(sql);

            //遍历多条数据的参数值
            for (Object[] single : args) {
                //对每条数据的问号设置值
                for (int i = 0; i < single.length; i++) {
                    ps.setObject(i+1,single[i]);
                }
                //将当前语句添加至批处理
                ps.addBatch();
            }

            //执行批处理，获得每条数据的执行结果
            int[] updateCount = ps.executeBatch();

            //如果获得结果的数量与传递的数据数量一致且每个结果的受影响行数都是1，则表示执行成功，此时可以提交事务
            if(updateCount.length==args.size() && Arrays.stream(updateCount).allMatch(num->num==1)){
                conn.commit();
            }else{
                //如果返回的执行结果不正确，则把标识置为false，且回滚事务
                result = false;
                conn.rollback();
            }
        } catch (SQLException e) {
            try {
                result = false;
//                e.printStackTrace();
                //批处理执行过程中，任何一个语句执行报错都要进行回滚
                conn.rollback();
            } catch (SQLException ex) {
                throw new RuntimeException(ex);
            }
        } finally {
            closed();
        }

        //返回最终结果
        return result;
    }

    /**
     * 执行单条语句查询
     * @param sql 要执行的语句
     * @param args 查询语句的参数值，顺序必须与sql中的问号顺序保持一致
     * @return
     */
    public static ResultSet executeQuerySql(String sql,Object... args){

        try {
            //获取连接并初始化预处理语句
            conn = getDefaultConn();
            ps = conn.prepareStatement(sql);

            //设置预处理语句的问号
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i+1,args[i]);
            }

            //执行查询
            ResultSet rs = ps.executeQuery();

            //返回结果集
            return rs;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
//            closed();
        }
    }
}
